Skip to content

Keep file I/O out of DefaultStorageFactory for trimmed builds - #47

Merged
hadashiA merged 1 commit into
mainfrom
claude/trimmable-file-storage
Nov 8, 2026
Merged

hadashiA merged 1 commit into
mainfrom
claude/trimmable-file-storage

Conversation

@hadashiA

@hadashiA hadashiA commented Nov 7, 2026

Copy link
Copy Markdown
Owner

Fixes #45

Problem

DatabaseLoadOptions.DefaultStorageFactory is rooted by every use of DatabaseLoadOptions, and its FileStream branch statically referenced PreadPageLoader. Its pread path (RandomAccess over SafeFileHandle) drags native file I/O symbols such as SystemNative_PReadV into every trimmed/AOT-compiled application, even ones that only read from a MemoryStream. Environments without those symbols (the reported godot-dn2cpp wasm export) cannot link DryDB at all; for everyone else it is dead weight in trimmed builds.

Fix

Move the FileStream handling into a public FileStorage.Factory (in DryDB.Storages), which handles FileStream and falls back to DefaultStorageFactory for everything else. OpenFileAsync swaps it in when the options still carry the default factory (a custom StorageFactory keeps winning), so file support is rooted only by callers that actually open files — essentially the shape proposed in the issue.

Breaking change

OpenAsync(fileStream) no longer picks PreadPageLoader implicitly. It throws NotSupportedException whose message points to the two replacements:

  • ReadOnlyDatabase.OpenFileAsync(path), or
  • new DatabaseLoadOptions { StorageFactory = FileStorage.Factory } when you need to pass an already opened FileStream.

Verification

  • Behavior checks: OpenAsync(MemoryStream), OpenFileAsync (default and with a custom StorageFactory, which is still honored), OpenAsync(FileStream) → guided NotSupportedException, and OpenAsync(FileStream) with FileStorage.Factory → works.
  • Trimming: a memory-only console app published with TrimMode=full runs correctly and its DryDB.dll contains no PreadPageLoader, FileStorage, RandomAccess, or OpenFileAsync references (control symbols DatabaseBuilder / InMemoryPageLoader remain).
  • dotnet test: 95/95 passing.

🤖 Generated with Claude Code

DefaultStorageFactory is rooted by every use of DatabaseLoadOptions, and
its FileStream branch statically referenced PreadPageLoader, whose pread
path (RandomAccess over SafeFileHandle) drags native file I/O symbols
such as SystemNative_PReadV into every trimmed or AOT-compiled
application — including ones that only ever read from a MemoryStream.
Environments without those symbols (e.g. godot-dn2cpp wasm exports)
could not link DryDB at all.

Move the FileStream handling into a public FileStorage.Factory that
OpenFileAsync swaps in when the options still carry the default factory,
so file support is rooted only by callers that actually open files.
A memory-only app trimmed with TrimMode=full now carries no
PreadPageLoader, RandomAccess, or SystemNative_PReadV references.

BREAKING: OpenAsync(fileStream) no longer picks PreadPageLoader
implicitly; it throws NotSupportedException with guidance to use
OpenFileAsync or set DatabaseLoadOptions.StorageFactory =
FileStorage.Factory.

Fixes #45

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hadashiA
hadashiA merged commit 6c44d27 into main Nov 8, 2026
1 check passed
@hadashiA
hadashiA deleted the claude/trimmable-file-storage branch November 8, 2026 01:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DefaultStorageFactory が FileStream を参照しているため、FileStream を使えない環境で DryDB を使えない

1 participant